package core

import (
	"github.com/xiaoqinghong/super_daemon/core/process"
	"os"
	"os/exec"
	user2 "os/user"
	"strconv"
	"syscall"
)

type processImpl struct {
	cmd  *exec.Cmd
	info *process.Info
}

func (p *processImpl) Run() (err error) {
	defer func() {
		p.info.LastError = err.Error()
		if err != nil || p.cmd.Process == nil || p.cmd.Process.Pid == 0 {
			p.info.Status = process.Failed
		}
	}()
	p.cmd.Stdout, err = os.OpenFile(p.info.StdoutLogFile, os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_APPEND, 0755)
	if err != nil {
		return
	}
	p.cmd.Stderr, err = os.OpenFile(p.info.StdoutErrFile, os.O_WRONLY|os.O_CREATE|os.O_SYNC|os.O_APPEND, 0755)
	if err != nil {
		return
	}
	user, err := user2.Lookup(p.info.User)
	if err != nil {
		return
	}
	uid, _ := strconv.Atoi(user.Uid)
	gid, _ := strconv.Atoi(user.Gid)
	p.cmd.SysProcAttr = &syscall.SysProcAttr{}
	p.cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
	if err = p.cmd.Run(); err != nil {
		return
	}
	p.info.Status = process.Running
	return
}

func (p *processImpl) Stop() (err error) {
	defer func() {
		p.info.LastError = err.Error()
		if err != nil && p.cmd.Process.Pid > 0 {
			p.info.Status = process.Failed
		}
	}()
	if err = p.cmd.Process.Kill(); err != nil {
		return err
	}
	p.info.Status = process.Stopped
	return
}

func (p *processImpl) Restart() (err error) {
	defer func() {
		p.info.LastError = err.Error()
		if err != nil && p.cmd.Process.Pid > 0 {
			p.info.Status = process.Failed
		}
	}()
	p.info.Status = process.Restarting
	if p.info.Status == process.Stopped {
		if err = p.Stop(); err != nil {
			return err
		}
	}
	//Start执行不会等待命令完成，Run会阻塞等待命令完成，所以这里使用run
	if err = p.Run(); err != nil {
		return err
	}
	return
}

func (p *processImpl) GetInfo() process.Info {
	return *p.info
}

func newProcess(cmd *exec.Cmd, info *process.Info) process.IProcess {
	p := &processImpl{
		cmd:  cmd,
		info: info,
	}
	return p
}
